package com.example.filemanager

import android.Manifest
import android.annotation.TargetApi
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.storage.StorageManager
import android.text.TextUtils
import android.text.format.Formatter
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.amaze.filemanager.fileoperations.filesystem.OpenMode
import com.amaze.filemanager.fileoperations.filesystem.StorageNaming
import com.amaze.filemanager.fileoperations.filesystem.StorageNaming.DeviceDescription
import com.amaze.filemanager.fileoperations.filesystem.usb.SingletonUsbOtg
import com.example.filemanager.command.DeleteFileCommand
import com.example.filemanager.command.ListFilesCommand
import com.example.filemanager.data.LayoutElementParcelable
import com.example.filemanager.data.StorageDirectoryParcelable
import com.example.filemanager.emun.FileType
import com.example.filemanager.ext.FileManager
import com.example.filemanager.files.FileUtils
import com.example.filemanager.filesystem.ExternalSdCardOperation
import com.example.filemanager.utils.DataUtils
import com.example.filemanager.utils.OTGUtil
import com.example.filemanager.utils.Utils
import java.io.File
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.regex.Pattern

class MainActivity : AppCompatActivity() {
    private val DEFAULT_FALLBACK_STORAGE_PATH = "/storage/sdcard0"
    val DIR_SEPARATOR = Pattern.compile("/")
    private val dataUtils: DataUtils = DataUtils.getInstance()
    private var list = mutableListOf<LayoutElementParcelable>()
    private val mSyncList = Collections.synchronizedCollection(list)
    private var mCount = 0
    var executorService: ExecutorService = Executors.newCachedThreadPool()
    //ConcurrentHashMap
    private var concurrentHashMap = ConcurrentHashMap<String,String>()
    private var mLogCount = 0
    private var mCountTv:TextView ?= null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val actualPath = /*FileProperties.remapPathForApi30OrAbove(cacheDir.path, false)*/"/storage/emulated/0"
        findViewById<Button>(R.id.vTest).setOnClickListener {
            val start = System.currentTimeMillis()
            FileManager.scanPhoneToGetAll(10*1024*1024, resultCallback ={
                runOnUiThread {
                    findViewById<TextView>(com.example.filemanager.R.id.vTvEmpty).text = "空文件：${FileManager.getFileList(FileType.APK).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvLager).text = "大文件：${FileManager.getFileList(FileType.LAGER_FILE).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvLog).text = "日志文件：${FileManager.getFileList(FileType.LOG).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvApk).text = "安装包：${FileManager.getFileList(FileType.APK).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvAuto).text = "音频文件：${FileManager.getFileList(FileType.AUTO).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvImage).text = "图像：${FileManager.getFileList(FileType.IMAGE).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvCompress).text = "压缩文件：${FileManager.getFileList(FileType.COMPRESS).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvTxt).text = "文档：${FileManager.getFileList(FileType.TXT).size}"
                    findViewById<TextView>(R.id.vTvScanSecond).text = "总消耗时间：${ (System.currentTimeMillis() - start)/1000.0 }S"
                    findViewById<TextView>(R.id.vTvStatus).text = "扫描完成"
                }
                Log.i("日志","总消耗时间：${ (System.currentTimeMillis() - start)/1000.0 }S")
            }, progressCallback = {total, current, item ->
                runOnUiThread {
                    findViewById<TextView>(com.example.filemanager.R.id.vTvEmpty).text = "空文件：${FileManager.getFileList(FileType.APK).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvLager).text = "大文件：${FileManager.getFileList(FileType.LAGER_FILE).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvLog).text = "日志文件：${FileManager.getFileList(FileType.LOG).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvApk).text = "安装包：${FileManager.getFileList(FileType.APK).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvAuto).text = "音频文件：${FileManager.getFileList(FileType.AUTO).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvImage).text = "图像：${FileManager.getFileList(FileType.IMAGE).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvCompress).text = "压缩文件：${FileManager.getFileList(FileType.COMPRESS).size}"
                    findViewById<TextView>(com.example.filemanager.R.id.vTvTxt).text = "文档：${FileManager.getFileList(FileType.TXT).size}"
                    findViewById<TextView>(R.id.vTvPercentage).text = "百分比：${current.toFloat()/total*100}%"
                    findViewById<TextView>(R.id.vTvStatus).text = "扫描中"
                    findViewById<TextView>(R.id.vTvScanName).text = item.desc
                    findViewById<TextView>(R.id.vTvScanSecond).text = "总消耗时间：${ (System.currentTimeMillis() - start)/1000.0 }S"
                }
            })
        }
        findViewById<Button>(R.id.vDelete).setOnClickListener {
            executorService.execute {
                for (item in mSyncList){
                    val it = item.generateBaseFile()
                    it.delete(this,false)
                }
            }
        }
    }

    fun getLageFileList(){
        FileManager.getLargeFile(10*1024*1024, showHideFile = true, progressCallback = { total: Int, current: Int, resultList: MutableList<LayoutElementParcelable>, item: LayoutElementParcelable ->
            Log.i("日志","文件信息：大小-${item.size},地址：${item.desc}")
        }, resultCallback = {filesList, isCache ->
            //Log.i("日志","扫描完成，文件数量为：${filesList.size},消耗时间为：${System.currentTimeMillis() - start}")
        })
    }

    fun getEndWith(){
        FileManager.getFilesByEndWidth(arrayListOf(".log"), progressCallback = { total: Int, current: Int, resultList: MutableList<LayoutElementParcelable>, item: LayoutElementParcelable ->
            Log.i("日志","执行：${current/(total.toFloat())}")
        })
    }

    override fun onDestroy() {
        super.onDestroy()
        FileManager.showDownMission()
    }

    private fun findView(path:String){
        if (concurrentHashMap[path] != null){
            return
        }
        concurrentHashMap[path] = path
        executorService.execute {
            //val currentOpenMode: Array<OpenMode?> = arrayOfNulls<com.amaze.filemanager.fileoperations.filesystem.OpenMode>(1)
            ListFilesCommand.listFiles(path, false, true,
                { mode ->
                    OpenMode.FILE
                    null
                }
            ) {
                val elem: LayoutElementParcelable? = createListParcelables(it);
                if (elem == null) null
                if ( (elem?.isDirectory == true)){
                    findView(elem?.desc)
                }else if (elem?.isDirectory == false && elem?.desc.endsWith(".log",true)){
                    if (elem != null) mSyncList.add(elem)
                    proCount()
                }
                null
            }
        }
    }

    private fun proCount(){
        synchronized(this){
            mCount += 1
            runOnUiThread(Runnable {
                mCountTv?.text = mCount.toString()
            })
        }
    }

    private fun createListParcelables(baseFile: HybridFileParcelable): LayoutElementParcelable? {
        if (dataUtils.isFileHidden(baseFile.getPath())) {
            return null
        }
        var size: String? = ""
        var longSize: Long = 0
        if (baseFile.isDirectory) {
            mCount++
        } else {
            if (baseFile.size !== -1L) {
                try {
                    longSize = baseFile.size
                    size = Formatter.formatFileSize(this, longSize)
                } catch (e: java.lang.NumberFormatException) {

                }
            }
        }
        return LayoutElementParcelable(
            this,
            baseFile.getName(this),
            baseFile.getPath(),
            baseFile.permission,
            baseFile.link,
            size,
            longSize,
            false, baseFile.date.toString() + "",
            baseFile.isDirectory,
            true,
            baseFile.getMode()
        )
    }

    /**
     * @return paths to all available volumes in the system (include emulated)
     */
    @Synchronized
    fun getStorageDirectories(): java.util.ArrayList<StorageDirectoryParcelable>? {
        val volumes: java.util.ArrayList<StorageDirectoryParcelable>
        volumes = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            getStorageDirectoriesNew()
        } else {
            getStorageDirectoriesLegacy()
        }
        val a = 0;
        if (/*isRootExplorer()*/ a == 0) {
            volumes.add(
                StorageDirectoryParcelable(
                    "/",
                    "",
                    R.drawable.ic_launcher_background
                )
            )
        }
        return volumes
    }

    /**
     * @return All available storage volumes (including internal storage, SD-Cards and USB devices)
     */
    @TargetApi(Build.VERSION_CODES.N)
    @Synchronized
    fun getStorageDirectoriesNew(): java.util.ArrayList<StorageDirectoryParcelable> {
        // Final set of paths
        val volumes: java.util.ArrayList<StorageDirectoryParcelable> =
            java.util.ArrayList<StorageDirectoryParcelable>()
        val sm = getSystemService(StorageManager::class.java)
        for (volume in sm.storageVolumes) {
            if (!volume.state.equals(Environment.MEDIA_MOUNTED, ignoreCase = true)
                && !volume.state.equals(Environment.MEDIA_MOUNTED_READ_ONLY, ignoreCase = true)
            ) {
                continue
            }
            val path: File = Utils.getVolumeDirectory(volume)
            var name = volume.getDescription(this)
            var icon: Int
            if (!volume.isRemovable) {
                icon = R.drawable.ic_launcher_background
            } else {
                // HACK: There is no reliable way to distinguish USB and SD external storage
                // However it is often enough to check for "USB" String
                if (name.uppercase(Locale.getDefault()).contains("USB") || path.path.uppercase(
                        Locale.getDefault()
                    ).contains("USB")
                ) {
                    icon = R.drawable.ic_launcher_background
                } else {
                    icon = R.drawable.ic_launcher_background
                }
            }
            volumes.add(StorageDirectoryParcelable(path.path, name, icon))
        }
        return volumes
    }

    /**
     * Returns all available SD-Cards in the system (include emulated)
     *
     *
     * Warning: Hack! Based on Android source code of version 4.3 (API 18) Because there was no
     * standard way to get it before android N
     *
     * @return All available SD-Cards in the system (include emulated)
     */
    @Synchronized
    fun getStorageDirectoriesLegacy(): java.util.ArrayList<StorageDirectoryParcelable> {
        val rv: MutableList<String> = java.util.ArrayList()

        // Primary physical SD-CARD (not emulated)
        val rawExternalStorage = System.getenv("EXTERNAL_STORAGE")
        // All Secondary SD-CARDs (all exclude primary) separated by ":"
        val rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE")
        // Primary emulated SD-CARD
        val rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET")
        if (TextUtils.isEmpty(rawEmulatedStorageTarget)) {
            // Device has physical external storage; use plain paths.
            if (TextUtils.isEmpty(rawExternalStorage)) {
                // EXTERNAL_STORAGE undefined; falling back to default.
                // Check for actual existence of the directory before adding to list
                if (File(DEFAULT_FALLBACK_STORAGE_PATH).exists()) {
                    rv.add(DEFAULT_FALLBACK_STORAGE_PATH)
                } else {
                    // We know nothing else, use Environment's fallback
                    rv.add(Environment.getExternalStorageDirectory().absolutePath)
                }
            } else {
                rv.add(rawExternalStorage)
            }
        } else {
            // Device has emulated storage; external storage paths should have
            // userId burned into them.
            val rawUserId: String
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
                rawUserId = ""
            } else {
                val path = Environment.getExternalStorageDirectory().absolutePath
                val folders: Array<String> = DIR_SEPARATOR.split(path)
                val lastFolder = folders[folders.size - 1]
                var isDigit = false
                try {
                    Integer.valueOf(lastFolder)
                    isDigit = true
                } catch (ignored: NumberFormatException) {
                }
                rawUserId = if (isDigit) lastFolder else ""
            }
            // /storage/emulated/0[1,2,...]
            if (TextUtils.isEmpty(rawUserId)) {
                rv.add(rawEmulatedStorageTarget)
            } else {
                rv.add(rawEmulatedStorageTarget + File.separator + rawUserId)
            }
        }
        // Add all secondary storages
        if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) {
            // All Secondary SD-CARDs splited into array
            val rawSecondaryStorages =
                rawSecondaryStoragesStr.split(File.pathSeparator).toTypedArray()
            Collections.addAll(rv, *rawSecondaryStorages)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkStoragePermission()) rv.clear()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            val strings: Array<String> = ExternalSdCardOperation.getExtSdCardPathsForActivity(this)
            for (s in strings) {
                val f = File(s)
                if (!rv.contains(s) && FileUtils.canListFiles(f)) rv.add(s)
            }
        }
        val usb: File? = getUsbDrive()
        if (usb != null && !rv.contains(usb.path)) rv.add(usb.path)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (SingletonUsbOtg.getInstance().isDeviceConnected) {
                rv.add(OTGUtil.PREFIX_OTG.toString() + "/")
            }
        }

        // Assign a label and icon to each directory
        val volumes: java.util.ArrayList<StorageDirectoryParcelable> =
            java.util.ArrayList<StorageDirectoryParcelable>()
        for (file in rv) {
            val f = File(file)
            @DrawableRes var icon: Int

            if ("/storage/emulated/legacy" == file || "/storage/emulated/0" == file || "/mnt/sdcard" == file) {
                icon = R.drawable.ic_launcher_background
            } else if ("/storage/sdcard1" == file) {
                icon = R.drawable.ic_launcher_background
            } else if ("/" == file) {
                icon = R.drawable.ic_launcher_background
            } else {
                icon = R.drawable.ic_launcher_background
            }
            @DeviceDescription val deviceDescription = StorageNaming.getDeviceDescriptionLegacy(f)
            val name: String =
                StorageNamingHelper.getNameForDeviceDescription(this, f, deviceDescription)
            volumes.add(StorageDirectoryParcelable(file, name, icon))
        }
        return volumes
    }

    fun getUsbDrive(): File? {
        var parent = File("/storage")
        try {
            for (f in parent.listFiles()) if (f.exists() && f.name.lowercase(Locale.getDefault())
                    .contains("usb") && f.canExecute()
            ) return f
        } catch (e: Exception) {
        }
        parent = File("/mnt/sdcard/usbStorage")
        if (parent.exists() && parent.canExecute()) return parent
        parent = File("/mnt/sdcard/usb_storage")
        return if (parent.exists() && parent.canExecute()) parent else null
    }

    private fun checkForExternalPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!checkStoragePermission()) {
                Log.i("日志","不存在权限")
                //requestStoragePermission(this, true)
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                Log.i("日志","11不存在权限")
                //requestAllFilesAccess(this)
            }
        }
    }

    private fun checkStoragePermission(): Boolean {

        // Verify that all required contact permissions have been granted.
        return (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
    }



}